作用域是原始碼中定義變數的區域,他規範了目前程式碼應該要去哪裡查找變數,而作用域又可分為 靜態作用域
與 動態作用域
,首先先來了解兩者的差別。
靜態作用域又稱作語法作用域(Lexical scoping),他在函數定義時就已經決定作用域,而且不會再改變,JavaScript 屬於此類。
以下為靜態作用域範例,運作步驟如下:
變數 num
賦予值 1。函式 fn2
,在函式內命名一個 變數 num
賦予值 2,因靜態作用域的關係,函式 fn2
中的 變數 num
,作用域只在 函式 fn2
中,接著呼叫 函式 fn1
。函式 fn1
內因沒有 變數 num
,又因靜態作用域的關係,所以會向外層(全域)查找,故 console.log(num); 顯示為 1
。// 靜態作用域範例
var num = 1;
function fn1() {
console.log(num); // 1
// 因靜態作用域,又因 fn1 沒有變數 num,所以會向外(全域)查找
}
function fn2() {
var num = 2;
//變數 num 作用域只在函式 fn2 中
fn1();
}
fn2();
動態作用域會在函式調用時才會決定作用域。
以下為動態作用域範例,運作步驟如下:
變數 num
賦予值 1。函式 fn2
,在函式內命名一個 變數 num
賦予值 2,接著呼叫 函式 fn1
。函式 fn1
內因沒有 變數 num
,又因動態作用域的關係 - 函式調用時才會決定作用域,所以會向上一層 函式 fn2
查找 變數 num
,故 console.log(num); 顯示為 2
。// 動態作用域範例
var num = 1;
function fn1() {
console.log(num); // 2
// 因動態作用域,在函式調用時才會決定作用域,所以會向上一層 fn2 宣告的位置找變數的值
}
function fn2() {
var num = 2;
fn1();
}
fn2();
若所有作用域都找不到變數時,則會出現 ReferenceError: 變數 is not defined
的錯誤訊息,範例如下。